package com.zl.learning.io;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.LinkedList;
import java.util.Queue;
import java.util.zip.*;

/**
 * @author zhaolei
 */
public class IODemo {

    private static String BASE_DIR = IODemo.class.getResource("/").getPath();

    /**
     * 演示示例：解决中文乱码
     */
    public static class BufferedReaderTest {
        public static void main(String[] args) {
            try (FileInputStream fis = new FileInputStream(BASE_DIR + "/data/data2/hello.txt");
                 InputStreamReader fr = new InputStreamReader(fis, StandardCharsets.UTF_8);
                 BufferedReader br = new BufferedReader(fr);) {
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 演示示例：使用BufferedReader和FileReader读取文本文件
     */
    public static class BufferedReaderTest2 {
        public static void main(String[] args) {
            try (FileReader fr = new FileReader(BASE_DIR + "/data/data2/hello.txt", StandardCharsets.UTF_8);
                 BufferedReader br = new BufferedReader(fr);) {
                //读取一行数据
                String line = null;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                System.out.println("文件不存在!");
            }
        }
    }

    public static class BufferedWriterTest {
        public static void main(String[] args) {
            try (FileWriter fw = new FileWriter(BASE_DIR + "/data/data2/hello.txt");
                 BufferedWriter bw = new BufferedWriter(fw);
                 FileReader fr = new FileReader(BASE_DIR + "/data/data2/hello.txt");
                 BufferedReader br = new BufferedReader(fr);) {

                bw.write("大家好！");
                bw.write("我正在学习BufferedWriter。");
                bw.newLine();
                bw.write("请多多指教！");
                bw.newLine();
                bw.flush();

                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                System.out.println("文件不存在!");
            }
        }
    }

    /**
     * 演示示例：二进制文件的读写
     */
    public static class ReadAndWriteBinaryFile {
        public static void main(String[] args) {
            try (FileInputStream fis = new FileInputStream(BASE_DIR + "/data/star.jpg");
                 DataInputStream dis = new DataInputStream(fis);
                 FileOutputStream fos = new FileOutputStream(BASE_DIR + "/data/new.jpg");
                 DataOutputStream dos = new DataOutputStream(fos);) {
                int temp;
                while ((temp = dis.read()) != -1) {
                    dos.write(temp);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 演示示例：zip文件读取
     */
    public static class ZipReadTest {
        public static void main(String[] args) {
            String dist = BASE_DIR + "/test";
            try (ZipInputStream zin = new ZipInputStream(new FileInputStream(BASE_DIR + "/test.zip"), Charset.forName("GBK"));) {
                ZipEntry ze;
                byte[] bytes = new byte[1024];
                while ((ze = zin.getNextEntry()) != null) {
                    if (ze.isDirectory()) {
                        final File file1 = new File(dist + "/" + ze.getName());
                        if (!file1.exists()) {
                            file1.mkdirs();
                        }
                    } else {
                        int len;
                        File distFile = new File(dist + "/" + ze.getName());
                        if (!distFile.getParentFile().exists()) {
                            distFile.getParentFile().mkdirs();
                        }
                        if (distFile.exists()) {
                            distFile.delete();
                        }
                        while ((len = zin.read(bytes)) != -1) {
                            try (FileOutputStream out = new FileOutputStream(distFile, true)) {
                                out.write(bytes, 0, len);
                            }
                        }
                    }
                    zin.closeEntry();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 演示：读取解压zip中指定文件
     */
    public static class ZipFileTest {
        public static void main(String[] args) {
            try (ZipFile zipFile = new ZipFile(BASE_DIR + "/test.zip")) {
                final ZipEntry entry = zipFile.getEntry("star.jpg");
                byte[] bytes = new byte[1024];
                try (InputStream in = zipFile.getInputStream(entry);
                     OutputStream out = new FileOutputStream(BASE_DIR + "/str.jpg", true)) {
                    int len;
                    while ((len = in.read(bytes)) != -1) {
                        out.write(bytes, 0, len);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 演示示例：zip文件创建
     */
    public static class ZipWriteTest {
        public static void main(String[] args) {
            String zipFile = BASE_DIR + "/test.zip";
            Queue<File> queue = new LinkedList<>();
            File soruce = new File(BASE_DIR + "/data");
            queue.offer(soruce);
            try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile))) {
                byte[] bytes = new byte[1024];
                File file;
                while ((file = queue.poll()) != null) {
                    final String name = soruce.toPath().relativize(file.toPath()).toString();
                    if (file.isDirectory()) {
                        if (!"".equals(name)) {
                            zos.putNextEntry(new ZipEntry(name + "/"));
                            zos.closeEntry();
                        }
                        final File[] files = file.listFiles();
                        if (files == null) {
                            continue;
                        }
                        for (File f : files) {
                            queue.offer(f);
                        }
                    } else {
                        zos.putNextEntry(new ZipEntry(name));
                        try (FileInputStream in = new FileInputStream(file)) {
                            int len;
                            while ((len = in.read(bytes)) != -1) {
                                zos.write(bytes, 0, len);
                            }
                        }
                        zos.closeEntry();
                    }
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 演示示例：GZip压缩解压缩
     */
    public static class GZipTest {
        public static void main(String[] args) {
            String str = "原长度压缩后字符串原字符串原字符串原字符串原字符串";
            System.out.println("原字符串：" + str);
            System.out.println("原长度：" + str.length());
            String compress = compress(str);
            System.out.println("压缩后字符串：" + compress);
            System.out.println("压缩后字符串长度：" + compress.length());
            String string = uncompress(compress);
            System.out.println("解压缩后字符串：" + string);
            System.out.println("原字符串：" + str);
        }

        /**
         * 使用GZip进行压缩
         */
        public static String compress(String primStr) {
            if (primStr == null || primStr.length() == 0) {
                return primStr;
            }
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            try (GZIPOutputStream gzip = new GZIPOutputStream(out);) {
                gzip.write(primStr.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }
            return new String(Base64.getEncoder().encode(out.toByteArray()));
        }

        /**
         * 使用gzip进行解压缩
         */
        public static String uncompress(String compressedStr) {
            if (compressedStr == null) {
                return null;
            }
            byte[] compressed = Base64.getDecoder().decode(compressedStr);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            try (GZIPInputStream ginzip = new GZIPInputStream(new ByteArrayInputStream(compressed));) {
                int len;
                byte[] bytes = new byte[256];
                while ((len = ginzip.read(bytes)) != -1) {
                    out.write(bytes, 0, len);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return out.toString();
        }
    }
}
